package top.milkbox.core;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;

/**
 * 使用过滤器来对用户发送的数据进行敏感词过滤
 * @author xiaoguo
 * @version 1.0
 * @createTime 2021年9月22日
 */
@WebFilter("/*")
public class SensitiveFilter implements Filter {

    // 存储敏感词汇的集合
    ArrayList<String> sensitiveStrings = new ArrayList<>();

    @Override
    public void init(FilterConfig config) throws ServletException {
        // 加载敏感词汇到内存
        ServletContext servletContext = config.getServletContext();
        String realPath = servletContext.getRealPath("/WEB-INF/classes/敏感词汇.txt");
        System.out.println(realPath);

        // 将信息读取到集合中
        BufferedReader bufferedReader = null;
        try {
            bufferedReader = new BufferedReader(new FileReader(realPath));
            String line = null;
            while ((line = bufferedReader.readLine()) != null) {
                sensitiveStrings.add(line);
            }
            System.out.println(sensitiveStrings.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 释放资源
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain chain) throws ServletException, IOException {

        // 放行前
        // 敏感词汇替换
        // 创建代理对象
        ServletRequest proxy_request = (ServletRequest) Proxy.newProxyInstance(servletRequest.getClass().getClassLoader(), servletRequest.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if ("getParameter".equals(method.getName())) {
                    // 增强getParameter()
                    // 执行方法，获取方法的返回值
                    String replace = (String) method.invoke(servletRequest, args);
                    // 替换掉敏感词
                    replace = replaceSensitive(replace, "*");
                    return replace;
                } else if ("getParameterMap".equals(method.getName())) {
                    //判断方法名是否是 getParameterMap
                    Map<String, String[]> parameterMap = (Map<String, String[]>) method.invoke(servletRequest, args);
                    // 遍历map
                    Set<String> keys = parameterMap.keySet();
                    for (String key : keys) {
                        String[] strings = parameterMap.get(key);
                        // 遍历map中值的数组
                        for (int i = 0; i < strings.length; i++) {
                            // 替换敏感词
                            strings[i] = replaceSensitive(strings[i], "*");
                        }
                    }
                    return parameterMap;

                } else if ("getParameterValues".equals(method.getName())) {
                    //判断方法名是否是 getParameterValue
                    String[] parameterValues = (String[]) method.invoke(servletRequest, args);
                    for (int i = 0; i < parameterValues.length; i++) {
                        // 替换敏感词
                        parameterValues[i] = replaceSensitive(parameterValues[i], "*");
                    }
                    return parameterValues;
                }


                // 如果调用的是对象的其他方法，则原样执行
                return method.invoke(servletRequest, args);
            }
        });

        // 将动态代理的request传入
        chain.doFilter(proxy_request, servletResponse); // 放行

        // 放行后

    }

    /**
     * 替换目标字符串中所含的敏感词
     * 敏感词列表在init方法里初始化
     *
     * @param oldString     要处理的字符串
     * @param replaceSymbol 替换的符号
     * @return 返回替换后的字符串，如果没有敏感词字等于原字符串
     */
    private String replaceSensitive(String oldString, String replaceSymbol) {
        if (oldString != null) {
            for (String sensitiveString : sensitiveStrings) {
                if (oldString.contains(sensitiveString)) {
                    oldString = oldString.replaceAll(sensitiveString, replaceSymbol);
                }
            }
        }
        return oldString;
    }

    @Override
    public void destroy() {

    }

}
